use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use crate::instruction::instruction::Instruction;
use crate::vm_thread::{VMFrame, VMThread};

pub struct vreturn {}

impl Instruction for vreturn {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        thread.stack.borrow_mut().pop();
    }

    fn to_string(&self) -> String {
        String::from("vreturn")
    }
}

pub struct ireturn {}

impl Instruction for ireturn {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        no_void_return(frame, thread);
    }
    fn to_string(&self) -> String {
        String::from("ireturn")
    }
}


pub struct areturn {}

impl Instruction for areturn {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        no_void_return(frame, thread);
    }
    fn to_string(&self) -> String {
        String::from("areturn")
    }
}

fn no_void_return(frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
    let mut rw_stack = thread.stack.borrow_mut();
    let old_frame = rw_stack.pop().unwrap();
    let caller_stack = rw_stack.last().unwrap().clone();

    caller_stack.borrow().operand_stack.borrow_mut().push(
        old_frame.borrow_mut().operand_stack.borrow_mut().pop().unwrap()
    );
}